1. Finding correct serial(for lazy ones:) Like an all other proggies you can also crack this one on the few different ways.
Here I'll explain only one, the most simplest way to find the correct serial!
Open W32dasm and disassemble the file...
Now click on the "Strn REF" button and search for some strings that can make
your life better :)
You must find "REGISTERED!" string, if not found it now!
When you click on it you'll see one address at the bottom of the window....note that address!
Now, save disassembly text file and look at the code at address that you note.
You'll see this...
:00401538 7606 jbe 00401540
:0040153A 81E9FFFFFF7F sub ecx, 7FFFFFFF
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401538(C)
|
:00401540 890D70974000 mov dword ptr [00409770], ecx
:00401546 390D88974000 cmp dword ptr [00409788], ecx
:0040154C 7563 jne 004015B1(1)
:0040154E 8D44240C lea eax, dword ptr [esp+0C]
* Possible StringData Ref from Data Obj ->"REGISTERED!" ===>> Here 'good code' starts
|
:00401552 686C844000 push 0040846C
:00401557 50 push eax
...
...
* Reference To: USER32.EnableWindow, Ord:00ABh ===>> Enable 'Get done listed' button
|
:00401587 8B3554B24000 mov esi, dword ptr [0040B254]
:0040158D FFD6 call esi
...
...
:004015AF FFD6 call esi ===>> The end of the code
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040154C(C)
|
:004015B1 5F pop edi(1)
:004015B2 5E pop esi
:004015B3 5B pop ebx
:004015B4 83C410 add esp, 00000010
:004015B7 C3 ret
You can see that conditional jump(1) just before good code take us to the end of the code!
JNE means -- Jump if NOT equal!...so what must be equal???
Look at the line above....Program compare something here!...so these two values must be
same to register the program!....probably one of these values has something with correct serial!
So let's see what can those numbers be...
First, type into textboxes any random values.
Here is, for example, what I type: Bjanes
ReFleXZ '99
998899
For serial number I always use "998899" 'coz it's easy to remember hex value of the same number.
Hex value of "998899" is "F3DF3". So remember this number.
Press "CTRL-D" to open Sice. Let's now set breakpoint at 401546....first we must enter to the programs code.
So type "bpx GetDlgItemTextA". Now press "Check" button. You're now back in Sice. Press "F11" to return to
the programs code. You can now delete breakpoint at GetDlgItemTextA so type "bc *". Now we must set breakpoint
at 401546 where program compares these two values; now, type "bpx 401546". Press "CTRL-D" again.
Now, you land exactly on the comparation routine!
...cmp dword ptr [00409788], ecx...
Now, type "D 409788" to see what program compares here. Hmm...you'll see(if you enter "998899" for
the code) in the data window(hex value of chars) "F3..3D..0F"! First, notice that all values stored in memory
are in the reverse form. So, that value is actually "0F3DF3"!
Hmm....I saw that number somewhere :)....yes, that's hex value of serial that I entered("998899")!
So if program here compares 'fake' serial with some number and after that is good/bad guy jump, this
second number must be hex value of our correct serial!...Now, look at the ecx register and write down
this second number. In my case ecx contains "276DFDD". Disable all breakpoints with "bd *" and leave Sice("CTRL-D") .
Now, open CConvert and convert that second number to decimal. Copy the result to the clipboard and go to
the crackme again!...now past the number to the "Code" texbox and press "Check" button.
BTW You can also convert hex to decimal in the Sice typeing "? hex_value"!
You'll the get the result that looks like this: ....hex_value.....decimal_value.....'ASCII'...
So that decimal value is your correct serial!
Hmm....where I stop explaining? :)....Yeah, you press the "Check" button and look this...
You type in the correct serial and the program is registred!
Great job!....but try to change the date and register the program with same serial!...you can't??
Hehe...Let's see why...
2. Making a KeyGen and understanding the code If you're really lazy, like me(I was writting this essay two weeks:), that don't even read this part. You have your correct code and that's all what you need.
But if you want to learn something new(and you really can do that on this crackme), go for a drink something and then come back :)
So....where to start?
Load the crackme and type whatever you want into textboxes; Press "CTRL-D" and set breakpoint at GetDlgItemTextA(if you really don't know..."bpx GetDlgItemTextA"). Now press the "Check" button. Sice breaks. Press "F11" once to return to the programs code. You can now disable breakpoint("bd *").
BTW We use the GetDlgItemTextA breakpoint to break Sice just when the program is reading your input from the textboxes.
You'll now see this part of code...
:00401400 68E8030000 push 000003E8
:00401405 A374974000 mov dword ptr [00409774], eax
:0040140A 51 push ecx
* Reference To: USER32.GetDlgItemTextA, Ord:00EDh
|
:0040140B FF1558B24000 Call dword ptr [0040B258] ;Here program reads text from first
textbox('Name') and returns lenght to the EAX
:00401411 A3E8974000 mov dword ptr [004097E8], eax ;Here program saves the lenght of a
<= string=You land here!
:00401416 E885FFFFFF call 004013A0 ;FIX THE LENGHT-- If the lenght is greater then
30 then use only first 30 chars for calculation
:0040141B 8B0DE8974000 mov ecx, dword ptr [004097E8] ;Move fixed lenght to the ECX
:00401421 8935EC974000 mov dword ptr [004097EC], esi ;Save ESI("1") to the memory
Here first part of calculation starts.
ESI is used as a counter (loop this routine 'lenght of name' times). When the ESI is same as ECX then exit the routine...
:00401427 3BCE cmp ecx, esi ;Is ESI same(or greater) as ECX??
:00401429 764A jbe 00401475 ;If yes, the jump to the end of the routine
:0040142B 8B15F0974000 mov edx, dword ptr [004097F0] ;EDX = Another counter; Get it from memory("1")
:00401431 8B1D70974000 mov ebx, dword ptr [00409770] ;EBX = Nothing yet
Now look carefuly at this part of code. Here program generates one number from user name that you entered.
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401473(C)
|
:00401437 0FBEBAF7974000 movsx edi, byte ptr [edx+004097F7](1) ;EDI = Next(first) char of user name
:0040143E 0FBE8257704000 movsx eax, byte ptr [edx+00407057] ;EAX = One char from memory
:00401445 0FAFF8 imul edi, eax ;Multiply these two chars; EDI = EDI * EAX
:00401448 0FBE861F704000 movsx eax, byte ptr [esi+0040701F] ;EAX = Another one char from memory
:0040144F 0FAFF8 imul edi, eax ;Multiply result with EAX; EDI = EDI * EAX
:00401452 0FAFFA imul edi, edx ;Again, multiply result with counter; EDI = EDI * EDX
:00401455 42 inc edx ;Incrase counter; EDX = EDX + 1
:00401456 03DF add ebx, edi ;Add final result to the EBX; EBX = EBX + EDI
:00401458 46 inc esi ;Incrase another counter; ESI = ESI + 1
:00401459 893D74974000 mov dword ptr [00409774], edi ;Save sub-result(result from this loop)
:0040145F 8915F0974000 mov dword ptr [004097F0], edx ;Save counter
:00401465 891D70974000 mov dword ptr [00409770], ebx ;Save final result;Sum of all
results(from all loops) :0040146B :0040146B 8935EC974000 mov dword ptr [004097EC], esi ;Save second counter
:00401471 3BF1 cmp esi, ecx ;Is 'counter' >= 'lenght of name'??
:00401473 72C2 jb 00401437 ;If yes then goto end; If not then loop this again(1)
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401429(C)
|
:00401475 5F pop edi ;This is the end of the routine
:00401476 5E pop esi
:00401477 5B pop ebx
:00401478 C3 ret ;Back to main routine
This was the first part of a calculation routine which final result is saved to memory at 409770. This number is really important 'coz it's part of our correct serial!
Let's now explain some things.
You probably don't understand what chars does program take at 40143E and 401448. Program takes first char, from string at memory address 407057. Second char program takes from another string at 40701F.
String at 407057 = " fQObVwNOankJ5skqJvae3Ae5jdoETu5n02J6Ez85430PNSDAPjDrYgFaze9VDRjq"
|<== This will be String1
String at 40701F = "?Etn5Pnc5AXi1DFlkYqnujsXNmvHdbcrqOoT8aaV5DkaymMRkPkoQ."
|<== This will be String2
First time program takes first char from both strings. Every next time next char from string was taken!
So what program does here?
1. Get the lenght of user name
2. Get next(first) from user name
3. Get next(first) char from String1
4. Multiply their hex values
5. Get next(first) char from String2
6. Multiply result(from previous multiplying) with hex value of char
7. Multiply result with a counter (sub_result)
8. Final_result = Final_result + sub_result
9. Incrase all counters
10. If NOT 'counter' = 'lenght_of_user_name' then loop this again; jump to the 2nd line
Hope you now understand this calculation better. So we can go to the another part.
Press "F10" key until you get on: ....00401478 C3 ret....Now, press F10 ones more.
You're now in the main code of calculation.
You see this piece of code....
:004019E4 C7057097400000000000 mov dword ptr [00409770], 00000000
:004019EE 8B74240C mov esi, dword ptr [esp+0C]
:004019F2 56 push esi
:004019F3 E8E8F9FFFF call 004013E0 ;This is calculation sub-routine for user name(we
just exit from here)
:004019F8 83C404 add esp, 00000004 ;'Fix' the stack <== You land here
:004019FB 56 push esi
:004019FC E87FFAFFFF call 00401480 ;This is second calc sub-routine, it calculates
number from a group
I'm NOT going to explain this second sub-routine 'coz it's exactly same as first one, where program calculates number from user name. Only difference is, that program here calculates number from group, not user name.
There is only one line important inside that calculation routine at 4019FC....
4019FC ...........................
..............calc routine.......
.............................................
00401507 add dword ptr [00409770], edi
.............................................
As you can remember at 409770 is stored result from first calc routine. In EDI is stored result from second routine.
Here program adds second result to first result and sum is saved back at 409770!...This number is very important
'coz it's first part of our correct serial. Now we need the second part.
Let's now analyze the rest of main routine...
:00401A01 83C404 add esp, 00000004 ;'Fix' the stack again
:00401A04 A1E8974000 mov eax, dword ptr [004097E8] ;Hmmm....moves lenght of name into EAX
:00401A09 83F803 cmp eax, 00000003 ;Is the lenght is less than 3?
:00401A0C 7307 jnb 00401A15 ;If yes, you're 'bad guy'!...If not then jump(2)
:00401A0E 33C0 xor eax, eax ;EAX = 0; 'Bad guy'
:00401A10 5F pop edi
:00401A11 5E pop esi
:00401A12 C21000 ret 0010 ;Exit the routine :(
Look this part of code carefuly 'coz it's very important...
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401A0C(C)
|
:00401A15 0FAFC0 imul eax, eax(2) ;EAX = EAX * EAX; EAX = lenght_of_name
* lenght_of_name
:00401A18 6A0A push 0000000A ;Parameter for GetDlgItemTextA
:00401A1A A374974000 mov dword ptr [00409774], eax ;Save EAX to the 409774!
:00401A1F A1AC974000 mov eax, dword ptr [004097AC] ;Get one number from the memory and
save it to the EAX!
:00401A24 6890974000 push 00409790 ;Parameter for GetDlgItemTextA
:00401A29 0FAF0574974000 imul eax, dword ptr [00409774] ;Multiply EAX with result of
multiplication at 401A15!
:00401A30 68EA030000 push 000003EA ;Parameter for GetDlgItemTextA
:00401A35 A37C974000 mov dword ptr [0040977C], eax ;Save the result to the memory!
:00401A3A 56 push esi ;Parameter for GetDlgItemTextA
Now, we also have second number for creating our correct serial. But how the program make this second number?
1. Result1 = lenght_of_name * lenght_of_name
2. Result2 = number_taken_from_memory * Result1
So, the Result2 is final result of this calculation. But, what's the number that program takes from memory at 401A1F?
I didn't see anywhere that program saves or changes this number or that memory location.
I also put into textboxes another informations and the number was same! So I thought that number in memory is CONSTANT value! I also made KeyGen with that number as a constant. But next day after I publish my KeyGen I
received Email telling me that KeyGen doesn't work! I test it day before and it works perfectly! But another day it doesn't
work! So I go to see where's the bug! And I found that number that I though it was constant CHANGED!! So I put
breakpoint on memory access to see where does program change it!..."bpm 4097AC". I press "Check" button and
Sice doesn't break! So where's the clue?...Number is changed, but program doesn't change it?...So I restart the program (breakpoint is still active), and look this.....Sice BREAKS!! So, this number is changed on the start of a program and
after that program stays same!
Here is the code where program changes that number...
:004015C3 53 push ebx
:004015C4 56 push esi
:004015C5 57 push edi
:004015C6 68D0974000 push 004097D0 ;Where to save the time
* Reference To: KERNEL32.GetLocalTime, Ord:00E2h <== Hmmm....Get time :)
|
:004015CB FF15C0B14000 Call dword ptr [0040B1C0] ;Call GetLocalTime
:004015D1 33C0 xor eax, eax ;EAX = 0
:004015D3 66A1D2974000 mov ax, word ptr [004097D2] ;Get the ordinal number of
current mounth!
:004015D9 0FBE88BF704000 movsx ecx, byte ptr [eax+004070BF] ;Get one char from memory
(explained later) /ECX\
:004015E0 33C0 xor eax, eax ;EAX = 0
:004015E2 890D74974000 mov dword ptr [00409774], ecx ;Save ECX to the memory
:004015E8 C744240C30000000 mov [esp+0C], 00000030 ;Nothing...
:004015F0 C744241003000000 mov [esp+10], 00000003 ;...Important
:004015F8 66A1D6974000 mov ax, word ptr [004097D6] ;Get current date!
:004015FE 33F6 xor esi, esi ;ESI = 0
:00401600 89742418 mov dword ptr [esp+18], esi ;Clear the...
:00401604 8974241C mov dword ptr [esp+1C], esi ;...stack
:00401608 C744241420174000 mov [esp+14], 00401720 ;Also...
:00401610 8B7C245C mov edi, dword ptr [esp+5C] ;...Nothing...
:00401614 6A66 push 00000066 ;...Important
:00401616 897C2424 mov dword ptr [esp+24], edi ;Still...
:0040161A 57 push edi ;...Nothing
:0040161B 0FBE809F704000 movsx eax, byte ptr [eax+0040709F] ;Get another char from memory
(explained later) /EAX\
:00401622 0FAFC1 imul eax, ecx ;Multiply these two chars
:00401625 A37C974000 mov dword ptr [0040977C], eax ;Save result to the memory
:0040162A A3AC974000 mov dword ptr [004097AC], eax ;Save result to the memory
<== Sice breaks here!
Let's analyze the code...
There are also two strings from where program takes those two chars. First char is taken at 4015D9 from string at 4070BF, and second char is taken at 40161B from string at 40709F. Let's see these two strings...
String at 4070BF = " 9803D2F7404E" <== This will be String1
String at 40709F = " F3A4BF3B0503FB8BCB4F49803D5C740" <== This will be String2
You can see that first string has 12 characters, so this string is used for mounth. Second string has 31 characters, so this one is used for date!
Let's now explain the calculation...
1. Get the current month
2. Get the char from String1 which is on the 'month' place
--- Example: If now is a second mounth, program will take second char from String1....that's "8"
If now is a eleventh mounth, program will take eleventh char from String1....that's "4"
3. Get the current date
4. Get the char from String2 witch is on the 'date' place (same as for mounth, only different String)
5. Multiply these two chars
6. Save result to the memory
Hope you understand this part of code. Let's now back to the 'real' programs code...
* Reference To: USER32.GetDlgItemTextA, Ord:00EDh
|
:00401A3B FF1558B24000 Call dword ptr [0040B258] ;Get the serial that you entered
:00401A41 6890974000 push 00409790 ;Save the location of serial
:00401A46 E8250F0000 call 00402970 ;Convert the serial to the hex!...result
is located in EAX!
:00401A4B 83C404 add esp, 00000004 ;'Fix' the stack
:00401A4E 8B0DA8974000 mov ecx, dword ptr [004097A8]
:00401A54 A388974000 mov dword ptr [00409788], eax ;Save hex value of serial into
the memory
:00401A59 51 push ecx
:00401A5A 56 push esi
:00401A5B E830F8FFFF call 00401290 ;Here is a call to the comparation routine
..... ..... ..... ..... ..... ..... ..... ..... ..... .....
.... nothing important after this line ....
..... ..... ..... ..... ..... ..... ..... ..... ..... .....
As you can see, here program reads serial from the textbox and then converst it to the hex.
Program then calls comparation routine at 401A5B, so let's see what's inside that call...
* Referenced by a CALL at Address:
|:00401A5B
|
:00401290 A19C974000 mov eax, dword ptr [0040979C] ;EAX = lenght of group
:00401295 8B0DE8974000 mov ecx, dword ptr [004097E8] ;ECX = lenght of name
:0040129B 8B542408 mov edx, dword ptr [esp+08]
:0040129F A374974000 mov dword ptr [00409774], eax ;Save the lenght of gruop
:004012A4 8B442404 mov eax, dword ptr [esp+04] ;EAX = Number generated from system date
:004012A8 52 push edx
:004012A9 50 push eax
:004012AA 890D7C974000 mov dword ptr [0040977C], ecx ;Save the lenght of name
:004012B0 C705A497400000000000 mov dword ptr [004097A4], 00000000
:004012BA E861020000 call 00401520 ;Call to a real comparation
:004012BF 83C408 add esp, 00000008
:004012C2 C3 ret
You already saw what's inside the call at 4012BA, but let's step inside again...
* Referenced by a CALL at Address:
|:004012BA
|
:00401520 83EC10 sub esp, 00000010 ;'Fix' the stack
:00401523 8B0D70974000 mov ecx, dword ptr [00409770] ;ECX = number generated from group
and user name
:00401529 030DAC974000 add ecx, dword ptr [004097AC];ECX = ECX + Number generated from date
:0040152F 53 push ebx
:00401530 56 push esi
:00401531 81F9FFFFFF7F cmp ecx, 7FFFFFFF ;Is result greater then 7FFFFFFF??
:00401537 57 push edi
:00401538 7606 jbe 00401540 ;If yes then execute next line
:0040153A 81E9FFFFFF7F sub ecx, 7FFFFFFF ;ECX = ECX - 7FFFFFFF
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401538(C)
|
:00401540 890D70974000 mov dword ptr [00409770], ecx ;Save the ECX to the memory
:00401546 390D88974000 cmp dword ptr [00409788], ecx ;Compare ECX with fake serial
:0040154C 7563 jne 004015B1 ;If they aren't equal then jump to the end
:0040154E 8D44240C lea eax, dword ptr [esp+0C]
* Possible StringData Ref from Data Obj ->"REGISTERED!"
|
:00401552 686C844000 push 0040846C
:00401557 50 push eax
So, what you can see from this essay? At the beginning, when program is loading, it generates one number based on system date. Program generates one number from user name. Then generates another one from group, After that program adds that two numbers and saves sum. Then check is lenght of name greater than 3. If not, then you're 'bad'! Lenght of group can be less that 3. You also mustn't put name of group into the textbox. Then program adds name generated from date to the sum of first two numbers.
That's our corerct serial in hex. You only must convert it to decimal and you have correct serial!